streamlit-nightly 1.42.3.dev20250301__py2.py3-none-any.whl → 1.43.1.dev20250306__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- streamlit/commands/navigation.py +138 -98
- streamlit/components/v1/component_arrow.py +3 -1
- streamlit/config.py +33 -11
- streamlit/dataframe_util.py +12 -4
- streamlit/elements/lib/built_in_chart_utils.py +3 -3
- streamlit/elements/lib/pandas_styler_utils.py +4 -4
- streamlit/elements/map.py +4 -2
- streamlit/elements/media.py +4 -2
- streamlit/elements/widgets/button.py +92 -28
- streamlit/elements/widgets/data_editor.py +4 -4
- streamlit/proto/ClientState_pb2.py +5 -5
- streamlit/proto/ClientState_pb2.pyi +7 -2
- streamlit/proto/NewSession_pb2.py +16 -16
- streamlit/proto/NewSession_pb2.pyi +8 -3
- streamlit/runtime/caching/hashing.py +1 -1
- streamlit/runtime/context.py +9 -0
- streamlit/static/index.html +1 -1
- streamlit/static/static/js/{FileDownload.esm.CUiEWbzl.js → FileDownload.esm.D90ZPlvX.js} +1 -1
- streamlit/static/static/js/{FileHelper.B6bBsK7b.js → FileHelper.B7wMHnJf.js} +1 -1
- streamlit/static/static/js/{FormClearHelper.B_9Ez6vr.js → FormClearHelper.DiTttn8n.js} +1 -1
- streamlit/static/static/js/{Hooks.VwVTTUgt.js → Hooks.DlsrQbRk.js} +1 -1
- streamlit/static/static/js/{InputInstructions.vmQUtJfB.js → InputInstructions.DABeMich.js} +1 -1
- streamlit/static/static/js/{ProgressBar.CrEUq34O.js → ProgressBar.B0_wzszZ.js} +2 -2
- streamlit/static/static/js/{RenderInPortalIfExists.uSIUxO87.js → RenderInPortalIfExists.Ct3yXHYV.js} +1 -1
- streamlit/static/static/js/{Toolbar.DDSvrD0E.js → Toolbar.BhJd2eBO.js} +1 -1
- streamlit/static/static/js/{base-input.JpWAqJ0N.js → base-input.BT0Fve4h.js} +1 -1
- streamlit/static/static/js/{checkbox.CWR-VT1j.js → checkbox.DytiXgc4.js} +2 -2
- streamlit/static/static/js/{createSuper.HcF5WnqF.js → createSuper.Dey_Nchq.js} +1 -1
- streamlit/static/static/js/{data-grid-overlay-editor.DminHUYw.js → data-grid-overlay-editor.DHaS0Xdu.js} +1 -1
- streamlit/static/static/js/{downloader._SGckIiV.js → downloader.CpXHg7_L.js} +1 -1
- streamlit/static/static/js/{es6.b4hv8be8.js → es6.B12jZN2H.js} +2 -2
- streamlit/static/static/js/{iframeResizer.contentWindow.BqakL47H.js → iframeResizer.contentWindow.Dp7IrKgg.js} +1 -1
- streamlit/static/static/js/{index.BL2LjKzZ.js → index.3smrX8Wb.js} +1 -1
- streamlit/static/static/js/index.6GcOZfbK.js +1 -0
- streamlit/static/static/js/index.9aouXH1R.js +1 -0
- streamlit/static/static/js/{index.cVjFgmUG.js → index.B0Dq5tyz.js} +1 -1
- streamlit/static/static/js/index.B0vUg2Y3.js +1 -0
- streamlit/static/static/js/index.BEjwL3_Z.js +1 -0
- streamlit/static/static/js/{index.C7GAgXnu.js → index.BFTv_Z_e.js} +1 -1
- streamlit/static/static/js/{index.C59Ya3CM.js → index.BWJyhyqF.js} +1 -1
- streamlit/static/static/js/{index.Dl9vrclR.js → index.Bb8aDqLI.js} +1 -1
- streamlit/static/static/js/{index.Cr9buiVv.js → index.Bd3HEJHM.js} +53 -53
- streamlit/static/static/js/index.BpUFb67U.js +1 -0
- streamlit/static/static/js/{index.CqU47T61.js → index.BpcIvL5C.js} +135 -170
- streamlit/static/static/js/{index.3M6TVRo2.js → index.BtGwo9mt.js} +1 -1
- streamlit/static/static/js/{index.D7yQTfz7.js → index.Bx2jHxuL.js} +1 -1
- streamlit/static/static/js/{index.Dph-QYbt.js → index.C8NedCpe.js} +2 -2
- streamlit/static/static/js/{index.D4vb0WQf.js → index.C8i44-aA.js} +1 -1
- streamlit/static/static/js/{index.Dev73dEg.js → index.CCzbz0re.js} +1 -1
- streamlit/static/static/js/{index.J3DKPewF.js → index.CKTE0OmI.js} +1 -1
- streamlit/static/static/js/{index.CpyxO9i-.js → index.Chro-AQL.js} +1 -1
- streamlit/static/static/js/{index.C-MV6qmR.js → index.D1pT2XNV.js} +1 -1
- streamlit/static/static/js/{index.CAxOUw_O.js → index.D2zBv6ha.js} +1 -1
- streamlit/static/static/js/{index.E5dz2muJ.js → index.D6F98iFW.js} +1 -1
- streamlit/static/static/js/{index.D4Nzp4K3.js → index.DDLiQS9D.js} +1 -1
- streamlit/static/static/js/{index.Cs86Rh1I.js → index.DVFO4dUf.js} +1 -1
- streamlit/static/static/js/index.DcZtLSnI.js +1 -0
- streamlit/static/static/js/index.Dnp2nMgW.js +1 -0
- streamlit/static/static/js/{index.SYnyLAtV.js → index.DpvAFLbG.js} +1 -1
- streamlit/static/static/js/{index.B5U4WHdm.js → index.Jj9qMZu5.js} +1 -1
- streamlit/static/static/js/{index.BFysNJg1.js → index.SSx319oy.js} +1 -1
- streamlit/static/static/js/{index.B4fN2DMS.js → index.U8Sox-zm.js} +1 -1
- streamlit/static/static/js/{index.BV5mA8ty.js → index.VRF0kACr.js} +5 -5
- streamlit/static/static/js/{index.BLVbwbeW.js → index.d4FK8xGd.js} +2 -2
- streamlit/static/static/js/index.ep0QJQk3.js +203 -0
- streamlit/static/static/js/index.f0VnAfoO.js +1 -0
- streamlit/static/static/js/index.l49xBSOh.js +73 -0
- streamlit/static/static/js/{index.Cb8hCZyO.js → index.v5B-faMq.js} +1 -1
- streamlit/static/static/js/{index.BgLbohq1.js → index.ydk_VgsB.js} +1 -1
- streamlit/static/static/js/{input.Dfd0mQ2M.js → input.D6h4j3mu.js} +2 -2
- streamlit/static/static/js/{memory.DFfwDfdX.js → memory.BE4D3Ruc.js} +1 -1
- streamlit/static/static/js/{mergeWith.B3E2fSKt.js → mergeWith.CfZBFCuT.js} +1 -1
- streamlit/static/static/js/{number-overlay-editor.DG8NE_c_.js → number-overlay-editor.BGuXja4w.js} +1 -1
- streamlit/static/static/js/{possibleConstructorReturn.CJ1f9cWL.js → possibleConstructorReturn.GfM_znXN.js} +1 -1
- streamlit/static/static/js/{sandbox.-T0hcQrx.js → sandbox.SNug_eHS.js} +1 -1
- streamlit/static/static/js/{textarea.CCPaMMRd.js → textarea.C9gOMijs.js} +2 -2
- streamlit/static/static/js/{timepicker.BrQl1vN-.js → timepicker.DnkicraE.js} +1 -1
- streamlit/static/static/js/{toConsumableArray.UwlRgC7o.js → toConsumableArray.CwiePuJG.js} +1 -1
- streamlit/static/static/js/{uniqueId.C5B1A1oI.js → uniqueId.BzT4v6M6.js} +1 -1
- streamlit/static/static/js/{useBasicWidgetState.Czrslgva.js → useBasicWidgetState.DKA7kWgD.js} +1 -1
- streamlit/static/static/js/{useOnInputChange.Dw8zLgsb.js → useOnInputChange.mkVXolML.js} +1 -1
- streamlit/static/static/js/{withFullScreenWrapper.t6HIFyK0.js → withFullScreenWrapper.CfWBIrsM.js} +1 -1
- {streamlit_nightly-1.42.3.dev20250301.dist-info → streamlit_nightly-1.43.1.dev20250306.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.42.3.dev20250301.dist-info → streamlit_nightly-1.43.1.dev20250306.dist-info}/RECORD +88 -88
- streamlit/static/static/js/index.BVLYWr2w.js +0 -1
- streamlit/static/static/js/index.BWfK_Obw.js +0 -203
- streamlit/static/static/js/index.BXSIv1Yj.js +0 -1
- streamlit/static/static/js/index.BhVVEe37.js +0 -1
- streamlit/static/static/js/index.BkDOb1MH.js +0 -73
- streamlit/static/static/js/index.C2ti2ux-.js +0 -1
- streamlit/static/static/js/index.CA_X6A4G.js +0 -1
- streamlit/static/static/js/index.CpN57BL8.js +0 -1
- streamlit/static/static/js/index.D6kHe3jN.js +0 -1
- streamlit/static/static/js/index._Q_M1OIX.js +0 -1
- {streamlit_nightly-1.42.3.dev20250301.data → streamlit_nightly-1.43.1.dev20250306.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.42.3.dev20250301.dist-info → streamlit_nightly-1.43.1.dev20250306.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.42.3.dev20250301.dist-info → streamlit_nightly-1.43.1.dev20250306.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.42.3.dev20250301.dist-info → streamlit_nightly-1.43.1.dev20250306.dist-info}/top_level.txt +0 -0
streamlit/commands/navigation.py
CHANGED
@@ -88,132 +88,172 @@ def navigation(
|
|
88
88
|
"""
|
89
89
|
Configure the available pages in a multipage app.
|
90
90
|
|
91
|
-
Call ``st.navigation`` in your entrypoint file to define the
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
91
|
+
Call ``st.navigation`` in your entrypoint file to define the available
|
92
|
+
pages for your app. ``st.navigation`` returns the current page, which can
|
93
|
+
be executed using ``.run()`` method.
|
94
|
+
|
95
|
+
When using ``st.navigation``, your entrypoint file (the file passed to
|
96
|
+
``streamlit run``) acts like a router or frame of common elements around
|
97
|
+
each of your pages. Streamlit executes the entrypoint file with every app
|
98
|
+
rerun. To execute the current page, you must call the ``.run()`` method on
|
99
99
|
the ``StreamlitPage`` object returned by ``st.navigation``.
|
100
100
|
|
101
|
-
The set of available pages can be
|
102
|
-
By default,
|
103
|
-
one page. This behavior can be
|
101
|
+
The set of available pages can be updated with each rerun for dynamic
|
102
|
+
navigation. By default, ``st.navigation`` displays the available pages in
|
103
|
+
the sidebar if there is more than one page. This behavior can be changed
|
104
|
+
using the ``position`` keyword argument.
|
104
105
|
|
105
|
-
|
106
|
-
ignore the ``pages/`` directory across all sessions.
|
106
|
+
As soon as any session of your app executes the ``st.navigation`` command,
|
107
|
+
your app will ignore the ``pages/`` directory (across all sessions).
|
107
108
|
|
108
109
|
Parameters
|
109
110
|
----------
|
110
|
-
pages :
|
111
|
-
The available pages for the app.
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
111
|
+
pages : list[page-like], dict[str, list[page-like]]
|
112
|
+
The available pages for the app.
|
113
|
+
|
114
|
+
To create a navigation menu with no sections or page groupings,
|
115
|
+
``pages`` must be a list of page-like objects. Page-like objects are
|
116
|
+
anything that can be passed to ``st.Page`` or a ``StreamlitPage``
|
117
|
+
object returned by ``st.Page``.
|
118
|
+
|
119
|
+
To create labeled sections or page groupings within the navigation
|
120
|
+
menu, ``pages`` must be a dictionary. Each key is the label of a
|
121
|
+
section and each value is the list of page-like objects for
|
122
|
+
that section.
|
123
|
+
|
124
|
+
When you use a string or path as a page-like object, they are
|
125
|
+
internally passed to ``st.Page`` and converted to ``StreamlitPage``
|
126
|
+
objects. In this case, the page will have the default title, icon, and
|
127
|
+
path inferred from its path or filename. To customize these attributes
|
128
|
+
for your page, initialize your page with ``st.Page``.
|
129
|
+
|
130
|
+
position : "sidebar" or "hidden"
|
131
|
+
The position of the navigation menu. If this is ``"sidebar"``
|
132
|
+
(default), the navigation widget appears at the top of the sidebar. If
|
133
|
+
this is ``"hidden"``, the navigation widget is not displayed.
|
128
134
|
|
129
|
-
|
130
|
-
|
131
|
-
- "sidebar" (default): Places the navigation at the top of the sidebar
|
132
|
-
- "hidden": Hides the navigation widget
|
133
|
-
Note: Navigation is always hidden when there's only one page.
|
135
|
+
If there is only one page in ``pages``, the navigation will be hidden
|
136
|
+
for any value of ``position``.
|
134
137
|
|
135
138
|
expanded : bool
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
139
|
+
Whether the navigation menu should be expanded. If this is ``False``
|
140
|
+
(default), the navigation menu will be collapsed and will include a
|
141
|
+
button to view more options when there are too many pages to display.
|
142
|
+
If this is ``True``, the navigation menu will always be expanded; no
|
143
|
+
button to collapse the menu will be displayed.
|
144
|
+
|
145
|
+
If ``st.navigation`` changes from ``expanded=True`` to
|
146
|
+
``expanded=False`` on a rerun, the menu will stay expanded and a
|
147
|
+
collapse button will be displayed.
|
141
148
|
|
142
149
|
Returns
|
143
150
|
-------
|
144
151
|
StreamlitPage
|
145
|
-
The
|
152
|
+
The current page selected by the user. To run the page, you must use
|
153
|
+
the ``.run()`` method on it.
|
146
154
|
|
147
155
|
Examples
|
148
156
|
--------
|
149
|
-
|
157
|
+
The following examples show different possible entrypoint files, each named
|
158
|
+
``streamlit_app.py``. An entrypoint file is passed to ``streamlit run``. It
|
159
|
+
manages your app's navigation and serves as a router between pages.
|
160
|
+
|
161
|
+
**Example 1: Use a callable or Python file as a page**
|
162
|
+
|
163
|
+
You can declare pages from callables or file paths. If you pass callables
|
164
|
+
or paths to ``st.navigation`` as a page-like objects, they are internally
|
165
|
+
converted to ``StreamlitPage`` objects using ``st.Page``. In this case, the
|
166
|
+
page titles, icons, and paths are inferred from the file or callable names.
|
167
|
+
|
168
|
+
``page_1.py`` (in the same directory as your entrypoint file):
|
169
|
+
|
170
|
+
>>> import streamlit as st
|
171
|
+
>>>
|
172
|
+
>>> st.title("Page 1")
|
173
|
+
|
174
|
+
``streamlit_app.py``:
|
175
|
+
|
150
176
|
>>> import streamlit as st
|
151
|
-
>>> pages = ["home.py", "about.py", "contact.py"]
|
152
|
-
>>> page = st.navigation(pages)
|
153
|
-
>>> page.run()
|
154
|
-
|
155
|
-
Using functions as pages:
|
156
|
-
>>> def home():
|
157
|
-
... st.title("Home")
|
158
|
-
>>> def about():
|
159
|
-
... st.title("About")
|
160
177
|
>>>
|
161
|
-
>>>
|
162
|
-
|
163
|
-
>>>
|
178
|
+
>>> def page_2():
|
179
|
+
... st.title("Page 2")
|
180
|
+
>>>
|
181
|
+
>>> pg = st.navigation(["page_1.py", page_2])
|
182
|
+
>>> pg.run()
|
183
|
+
|
184
|
+
.. output::
|
185
|
+
https://doc-navigation-example-1.streamlit.app/
|
186
|
+
height: 200px
|
187
|
+
|
188
|
+
**Example 2: Group pages into sections and customize them with ``st.Page``**
|
164
189
|
|
165
|
-
|
190
|
+
You can use a dictionary to create sections within your navigation menu. In
|
191
|
+
the following example, each page is similar to Page 1 in Example 1, and all
|
192
|
+
pages are in the same directory. However, you can use Python files from
|
193
|
+
anywhere in your repository. ``st.Page`` is used to give each page a custom
|
194
|
+
title. For more information, see |st.Page|_.
|
195
|
+
|
196
|
+
Directory structure:
|
197
|
+
|
198
|
+
>>> your_repository/
|
199
|
+
>>> ├── create_account.py
|
200
|
+
>>> ├── learn.py
|
201
|
+
>>> ├── manage_account.py
|
202
|
+
>>> ├── streamlit_app.py
|
203
|
+
>>> └── trial.py
|
204
|
+
|
205
|
+
``streamlit_app.py``:
|
206
|
+
|
207
|
+
>>> import streamlit as st
|
208
|
+
>>>
|
166
209
|
>>> pages = {
|
167
|
-
... "
|
168
|
-
...
|
210
|
+
... "Your account": [
|
211
|
+
... st.Page("create_account.py", title="Create your account"),
|
212
|
+
... st.Page("manage_account.py", title="Manage your account"),
|
213
|
+
... ],
|
214
|
+
... "Resources": [
|
215
|
+
... st.Page("learn.py", title="Learn about us"),
|
216
|
+
... st.Page("trial.py", title="Try it out"),
|
217
|
+
... ],
|
169
218
|
... }
|
170
|
-
>>>
|
171
|
-
>>>
|
219
|
+
>>>
|
220
|
+
>>> pg = st.navigation(pages)
|
221
|
+
>>> pg.run()
|
222
|
+
|
223
|
+
.. output::
|
224
|
+
https://doc-navigation-example-2.streamlit.app/
|
225
|
+
height: 300px
|
226
|
+
|
227
|
+
**Example 3: Stateful widgets across multiple pages**
|
172
228
|
|
173
|
-
|
229
|
+
Call widget functions in your entrypoint file when you want a widget to be
|
230
|
+
stateful across pages. Assign keys to your common widgets and access their
|
231
|
+
values through Session State within your pages.
|
232
|
+
|
233
|
+
``streamlit_app.py``:
|
234
|
+
|
235
|
+
>>> import streamlit as st
|
236
|
+
>>>
|
174
237
|
>>> def page1():
|
175
|
-
|
238
|
+
>>> st.write(st.session_state.foo)
|
239
|
+
>>>
|
176
240
|
>>> def page2():
|
177
|
-
|
241
|
+
>>> st.write(st.session_state.bar)
|
178
242
|
>>>
|
179
|
-
>>> #
|
180
|
-
>>> st.
|
181
|
-
>>> st.
|
243
|
+
>>> # Widgets shared by all the pages
|
244
|
+
>>> st.sidebar.selectbox("Foo", ["A", "B", "C"], key="foo")
|
245
|
+
>>> st.sidebar.checkbox("Bar", key="bar")
|
182
246
|
>>>
|
183
|
-
>>>
|
184
|
-
>>>
|
247
|
+
>>> pg = st.navigation([page1, page2])
|
248
|
+
>>> pg.run()
|
185
249
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
250
|
+
.. output::
|
251
|
+
https://doc-navigation-multipage-widgets.streamlit.app/
|
252
|
+
height: 350px
|
253
|
+
|
254
|
+
.. |st.Page| replace:: ``st.Page``
|
255
|
+
.. _st.Page: https://docs.streamlit.io/develop/api-reference/navigation/st.page
|
191
256
|
|
192
|
-
Mixed usage with Path and sections:
|
193
|
-
>>> pages = {
|
194
|
-
... "Main": [Path("home.py"), about_func],
|
195
|
-
... "Info": [st.Page(Path("help.py"), title="Help Center")],
|
196
|
-
... }
|
197
|
-
>>> page = st.navigation(pages)
|
198
|
-
>>> page.run()
|
199
|
-
|
200
|
-
Raises
|
201
|
-
------
|
202
|
-
StreamlitAPIException
|
203
|
-
In the following cases:
|
204
|
-
- No pages provided
|
205
|
-
- Multiple pages set as default
|
206
|
-
- Duplicate URL pathnames
|
207
|
-
- Invalid page type provided
|
208
|
-
|
209
|
-
Notes
|
210
|
-
-----
|
211
|
-
- File paths can be relative or absolute
|
212
|
-
- Function names are used as default page titles
|
213
|
-
- URL pathnames must be unique across all pages
|
214
|
-
- Only one page can be set as default
|
215
|
-
- The first page is automatically set as default if none specified
|
216
|
-
- Common widgets should be defined in the entrypoint file for state sharing
|
217
257
|
"""
|
218
258
|
# Disable the use of the pages feature (ie disregard v1 behavior of Multipage Apps)
|
219
259
|
PagesManager.uses_pages_directory = False
|
@@ -135,5 +135,7 @@ def arrow_proto_to_dataframe(proto: ArrowTableProto) -> DataFrame:
|
|
135
135
|
columns = dataframe_util.convert_arrow_bytes_to_pandas_df(proto.columns)
|
136
136
|
|
137
137
|
return pd.DataFrame(
|
138
|
-
data.
|
138
|
+
data.to_numpy(),
|
139
|
+
index=index.to_numpy().T.tolist(),
|
140
|
+
columns=columns.to_numpy().T.tolist(),
|
139
141
|
)
|
streamlit/config.py
CHANGED
@@ -469,22 +469,35 @@ def _logger_message_format() -> str:
|
|
469
469
|
return "%(asctime)s %(message)s"
|
470
470
|
|
471
471
|
|
472
|
-
_create_option(
|
472
|
+
@_create_option(
|
473
473
|
"logger.enableRich",
|
474
|
-
description="""
|
475
|
-
Controls whether uncaught app exceptions are logged via the rich library.
|
476
|
-
|
477
|
-
If True and if rich is installed, exception tracebacks will be logged with
|
478
|
-
syntax highlighting and formatting. Rich tracebacks are easier to read and
|
479
|
-
show more code than standard Python tracebacks.
|
480
|
-
|
481
|
-
If set to False, the default Python traceback formatting will be used.
|
482
|
-
""",
|
483
|
-
default_val=False,
|
484
474
|
visibility="hidden",
|
485
475
|
type_=bool,
|
486
476
|
scriptable=True,
|
487
477
|
)
|
478
|
+
def _logger_enable_rich() -> bool:
|
479
|
+
"""
|
480
|
+
Controls whether uncaught app exceptions are logged via the rich library.
|
481
|
+
|
482
|
+
If True and if rich is installed, exception tracebacks will be logged with
|
483
|
+
syntax highlighting and formatting. Rich tracebacks are easier to read and
|
484
|
+
show more code than standard Python tracebacks.
|
485
|
+
|
486
|
+
If set to False, the default Python traceback formatting will be used.
|
487
|
+
|
488
|
+
Defaults to True if rich is installed, False otherwise.
|
489
|
+
"""
|
490
|
+
try:
|
491
|
+
import rich # noqa: F401
|
492
|
+
|
493
|
+
# Rich is importable, activate rich logging.
|
494
|
+
return True
|
495
|
+
except Exception:
|
496
|
+
# We are extra broad in catching exceptions here because we don't want
|
497
|
+
# that this causes Streamlit to crash if there is any unexpected
|
498
|
+
# exception thrown by the import
|
499
|
+
return False
|
500
|
+
|
488
501
|
|
489
502
|
# Config Section: Client #
|
490
503
|
|
@@ -1089,6 +1102,15 @@ _create_option(
|
|
1089
1102
|
visibility="hidden",
|
1090
1103
|
)
|
1091
1104
|
|
1105
|
+
_create_option(
|
1106
|
+
"theme.showSidebarSeparator",
|
1107
|
+
description="""
|
1108
|
+
Whether to show a vertical separator between the sidebar and the main content.
|
1109
|
+
""",
|
1110
|
+
type_=bool,
|
1111
|
+
visibility="hidden",
|
1112
|
+
)
|
1113
|
+
|
1092
1114
|
# Config Section: Secrets #
|
1093
1115
|
|
1094
1116
|
_create_section("secrets", "Secrets configuration.")
|
streamlit/dataframe_util.py
CHANGED
@@ -67,9 +67,14 @@ _MAX_UNEVALUATED_DF_ROWS = 10000
|
|
67
67
|
|
68
68
|
_PANDAS_DATA_OBJECT_TYPE_RE: Final = re.compile(r"^pandas.*$")
|
69
69
|
|
70
|
-
_DASK_DATAFRAME: Final = "dask.dataframe.
|
71
|
-
|
72
|
-
|
70
|
+
_DASK_DATAFRAME: Final = "dask.dataframe.dask_expr._collection.DataFrame"
|
71
|
+
_DASK_SERIES: Final = "dask.dataframe.dask_expr._collection.Series"
|
72
|
+
_DASK_INDEX: Final = "dask.dataframe.dask_expr._collection.Index"
|
73
|
+
# Dask removed the old legacy types, to support older and newer versions
|
74
|
+
# we are still supporting the old an new types.
|
75
|
+
_DASK_DATAFRAME_LEGACY: Final = "dask.dataframe.core.DataFrame"
|
76
|
+
_DASK_SERIES_LEGACY: Final = "dask.dataframe.core.Series"
|
77
|
+
_DASK_INDEX_LEGACY: Final = "dask.dataframe.core.Index"
|
73
78
|
_DUCKDB_RELATION: Final = "duckdb.duckdb.DuckDBPyRelation"
|
74
79
|
_MODIN_DF_TYPE_STR: Final = "modin.pandas.dataframe.DataFrame"
|
75
80
|
_MODIN_SERIES_TYPE_STR: Final = "modin.pandas.series.Series"
|
@@ -377,8 +382,11 @@ def is_dask_object(obj: object) -> bool:
|
|
377
382
|
"""True if obj is a Dask DataFrame, Series, or Index."""
|
378
383
|
return (
|
379
384
|
is_type(obj, _DASK_DATAFRAME)
|
385
|
+
or is_type(obj, _DASK_DATAFRAME_LEGACY)
|
380
386
|
or is_type(obj, _DASK_SERIES)
|
387
|
+
or is_type(obj, _DASK_SERIES_LEGACY)
|
381
388
|
or is_type(obj, _DASK_INDEX)
|
389
|
+
or is_type(obj, _DASK_INDEX_LEGACY)
|
382
390
|
)
|
383
391
|
|
384
392
|
|
@@ -498,7 +506,7 @@ def _fix_column_naming(data_df: DataFrame) -> DataFrame:
|
|
498
506
|
# Pandas automatically names the first column with 0 if it is not named.
|
499
507
|
# We rename it to "value" to make it more descriptive if there is only
|
500
508
|
# one column in the dataframe.
|
501
|
-
data_df.rename(columns={0: "value"}
|
509
|
+
data_df = data_df.rename(columns={0: "value"})
|
502
510
|
return data_df
|
503
511
|
|
504
512
|
|
@@ -567,7 +567,7 @@ def _maybe_reset_index_in_place(
|
|
567
567
|
x_column = df.index.name
|
568
568
|
|
569
569
|
df.index.name = x_column
|
570
|
-
df.reset_index(inplace=True)
|
570
|
+
df.reset_index(inplace=True) # noqa: PD002
|
571
571
|
|
572
572
|
return x_column
|
573
573
|
|
@@ -598,7 +598,7 @@ def _maybe_convert_color_column_in_place(df: pd.DataFrame, color_column: str | N
|
|
598
598
|
if color_column is None or len(df[color_column]) == 0:
|
599
599
|
return
|
600
600
|
|
601
|
-
first_color_datum = df[color_column].
|
601
|
+
first_color_datum = df[color_column].iloc[0]
|
602
602
|
|
603
603
|
if is_hex_color_like(first_color_datum):
|
604
604
|
# Hex is already CSS-valid.
|
@@ -988,7 +988,7 @@ def _get_color_encoding(
|
|
988
988
|
|
989
989
|
# If the 0th element in the color column looks like a color, we'll use the color column's
|
990
990
|
# values as the colors in our chart.
|
991
|
-
elif len(df[color_column]) and is_color_like(df[color_column].
|
991
|
+
elif len(df[color_column]) and is_color_like(df[color_column].iloc[0]):
|
992
992
|
color_range = [to_css_color(c) for c in df[color_column].unique()]
|
993
993
|
color_enc["scale"] = alt.Scale(range=color_range)
|
994
994
|
# Don't show the color legend, because it will just show text with the color values,
|
@@ -139,7 +139,7 @@ def _marshall_styles(
|
|
139
139
|
cellstyle = styles["cellstyle"]
|
140
140
|
cellstyle = _trim_pandas_styles(cellstyle)
|
141
141
|
for style in cellstyle:
|
142
|
-
rule = _pandas_style_to_css("cell_style", style, styler.uuid)
|
142
|
+
rule = _pandas_style_to_css("cell_style", style, styler.uuid, separator="_")
|
143
143
|
css_rules.append(rule)
|
144
144
|
|
145
145
|
if len(css_rules) > 0:
|
@@ -168,7 +168,7 @@ def _pandas_style_to_css(
|
|
168
168
|
style_type: str,
|
169
169
|
style: Mapping[str, Any],
|
170
170
|
uuid: str,
|
171
|
-
separator: str = "",
|
171
|
+
separator: str = "_",
|
172
172
|
) -> str:
|
173
173
|
"""Convert pandas.Styler translated style to CSS.
|
174
174
|
|
@@ -189,7 +189,7 @@ def _pandas_style_to_css(
|
|
189
189
|
"""
|
190
190
|
declarations = []
|
191
191
|
for css_property, css_value in style["props"]:
|
192
|
-
declaration = css_property.strip() + ": " + css_value.strip()
|
192
|
+
declaration = str(css_property).strip() + ": " + str(css_value).strip()
|
193
193
|
declarations.append(declaration)
|
194
194
|
|
195
195
|
table_selector = f"#T_{uuid}"
|
@@ -269,6 +269,6 @@ def _use_display_values(df: DataFrame, styles: Mapping[str, Any]) -> DataFrame:
|
|
269
269
|
if "id" in cell:
|
270
270
|
if match := cell_selector_regex.match(cell["id"]):
|
271
271
|
r, c = map(int, match.groups())
|
272
|
-
new_df.
|
272
|
+
new_df.iloc[r, c] = str(cell["display_value"])
|
273
273
|
|
274
274
|
return new_df
|
streamlit/elements/map.py
CHANGED
@@ -361,7 +361,7 @@ def _get_lat_or_lon_col_name(
|
|
361
361
|
# (Read about ExtensionArrays here: # https://pandas.pydata.org/community/blog/extension-arrays.html)
|
362
362
|
# However, after a performance test I found the solution below runs basically as
|
363
363
|
# fast as .values.any().
|
364
|
-
if any(data[col_name].
|
364
|
+
if any(data[col_name].isna().array):
|
365
365
|
raise StreamlitAPIException(
|
366
366
|
f"Column {col_name} is not allowed to contain null values, such "
|
367
367
|
"as NaN, NaT, or None."
|
@@ -421,7 +421,9 @@ def _convert_color_arg_or_column(
|
|
421
421
|
|
422
422
|
if color_col_name is not None:
|
423
423
|
# Convert color column to the right format.
|
424
|
-
if len(data[color_col_name]) > 0 and is_color_like(
|
424
|
+
if len(data[color_col_name]) > 0 and is_color_like(
|
425
|
+
data[color_col_name].iloc[0]
|
426
|
+
):
|
425
427
|
# Use .loc[] to avoid a SettingWithCopyWarning in some cases.
|
426
428
|
data.loc[:, color_col_name] = data.loc[:, color_col_name].map(
|
427
429
|
to_int_color_tuple
|
streamlit/elements/media.py
CHANGED
@@ -103,7 +103,8 @@ class MediaMixin:
|
|
103
103
|
|
104
104
|
format : str
|
105
105
|
The MIME type for the audio file. This defaults to ``"audio/wav"``.
|
106
|
-
For more information, see
|
106
|
+
For more information about MIME types, see
|
107
|
+
https://www.iana.org/assignments/media-types/media-types.xhtml.
|
107
108
|
|
108
109
|
start_time: int, float, timedelta, str, or None
|
109
110
|
The time from which the element should start playing. This can be
|
@@ -238,7 +239,8 @@ class MediaMixin:
|
|
238
239
|
|
239
240
|
format : str
|
240
241
|
The MIME type for the video file. This defaults to ``"video/mp4"``.
|
241
|
-
For more information, see
|
242
|
+
For more information about MIME types, see
|
243
|
+
https://www.iana.org/assignments/media-types/media-types.xhtml.
|
242
244
|
|
243
245
|
start_time: int, float, timedelta, str, or None
|
244
246
|
The time from which the element should start playing. This can be
|
@@ -307,20 +307,31 @@ class ButtonMixin:
|
|
307
307
|
.. |st.markdown| replace:: ``st.markdown``
|
308
308
|
.. _st.markdown: https://docs.streamlit.io/develop/api-reference/text/st.markdown
|
309
309
|
|
310
|
-
data : str
|
311
|
-
The contents of the file to be downloaded.
|
312
|
-
|
310
|
+
data : str, bytes, or file
|
311
|
+
The contents of the file to be downloaded.
|
312
|
+
|
313
|
+
To prevent unncecessary recomputation, use caching when converting
|
314
|
+
your data for download. For more information, see the Example 1
|
315
|
+
below.
|
313
316
|
|
314
317
|
file_name: str
|
315
318
|
An optional string to use as the name of the file to be downloaded,
|
316
|
-
such as
|
319
|
+
such as ``"my_file.csv"``. If not specified, the name will be
|
317
320
|
automatically generated.
|
318
321
|
|
319
322
|
mime : str or None
|
320
|
-
The MIME type of the data. If None,
|
321
|
-
|
322
|
-
|
323
|
-
|
323
|
+
The MIME type of the data. If this is ``None`` (default), Streamlit
|
324
|
+
sets the MIME type depending on the value of ``data`` as follows:
|
325
|
+
|
326
|
+
- If ``data`` is a string or textual file (i.e. ``str`` or
|
327
|
+
``io.TextIOWrapper`` object), Streamlit uses the "text/plain"
|
328
|
+
MIME type.
|
329
|
+
- If ``data`` is a binary file or bytes (i.e. ``bytes``,
|
330
|
+
``io.BytesIO``, ``io.BufferedReader``, or ``io.RawIOBase``
|
331
|
+
object), Streamlit uses the "application/octet-stream" MIME type.
|
332
|
+
|
333
|
+
For more information about MIME types, see
|
334
|
+
https://www.iana.org/assignments/media-types/media-types.xhtml.
|
324
335
|
|
325
336
|
key : str or int
|
326
337
|
An optional string or integer to use as the unique key for the widget.
|
@@ -404,45 +415,98 @@ class ButtonMixin:
|
|
404
415
|
|
405
416
|
Examples
|
406
417
|
--------
|
407
|
-
Download a
|
418
|
+
**Example 1: Download a dataframe as a CSV file**
|
419
|
+
|
420
|
+
When working with a large dataframe, it's recommended to fetch your
|
421
|
+
data with a cached function. When working with a download button, it's
|
422
|
+
similarly recommended to convert your data into a downloadable format
|
423
|
+
with a cached function. Caching ensures that the app reruns
|
424
|
+
effeciently.
|
408
425
|
|
409
426
|
>>> import streamlit as st
|
427
|
+
>>> import pandas as pd
|
428
|
+
>>> import numpy as np
|
429
|
+
>>>
|
430
|
+
>>> @st.cache_data
|
431
|
+
>>> def get_data():
|
432
|
+
>>> df = pd.DataFrame(
|
433
|
+
... np.random.randn(50, 20), columns=("col %d" % i for i in range(20))
|
434
|
+
... )
|
435
|
+
>>> return df
|
410
436
|
>>>
|
411
437
|
>>> @st.cache_data
|
412
|
-
|
413
|
-
|
414
|
-
... return df.to_csv().encode("utf-8")
|
438
|
+
>>> def convert_for_download(df):
|
439
|
+
>>> return df.to_csv().encode("utf-8")
|
415
440
|
>>>
|
416
|
-
>>>
|
441
|
+
>>> df = get_data()
|
442
|
+
>>> csv = convert_for_download(df)
|
417
443
|
>>>
|
418
444
|
>>> st.download_button(
|
419
|
-
... label="Download
|
445
|
+
... label="Download CSV",
|
420
446
|
... data=csv,
|
421
|
-
... file_name="
|
447
|
+
... file_name="data.csv",
|
422
448
|
... mime="text/csv",
|
449
|
+
... icon=":material/download:",
|
423
450
|
... )
|
424
451
|
|
425
|
-
|
452
|
+
.. output::
|
453
|
+
https://doc-download-button-csv.streamlit.app/
|
454
|
+
height: 200px
|
426
455
|
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
456
|
+
**Example 2: Download a string as a text file**
|
457
|
+
|
458
|
+
If you pass a string to the ``data`` argument, Streamlit will
|
459
|
+
automatically use the "text/plain" MIME type.
|
460
|
+
|
461
|
+
When you have a widget (like a text area) affecting the value of your
|
462
|
+
download, it's recommended to use another button to prepare the
|
463
|
+
download. In this case, use ``on_click="ignore"`` in your download
|
464
|
+
button to prevent the download button from rerunning your app. This
|
465
|
+
turns the download button into a frontend-only element that can be
|
466
|
+
nested in another button.
|
431
467
|
|
432
|
-
|
468
|
+
Without a preparation button, a user can type something into the text
|
469
|
+
area and immediately click the download button. Because a download is
|
470
|
+
initiated concurrently with the app rerun, this can create a race-like
|
471
|
+
condition where the user doesn't see the updated data in their
|
472
|
+
download.
|
473
|
+
|
474
|
+
.. important::
|
475
|
+
Even when you prevent your download button from triggering a rerun,
|
476
|
+
another widget with a pending change can still trigger a rerun. For
|
477
|
+
example, if a text area has a pending change when a user clicks a
|
478
|
+
download button, the text area will trigger a rerun.
|
433
479
|
|
434
480
|
>>> import streamlit as st
|
435
481
|
>>>
|
436
|
-
>>>
|
437
|
-
>>>
|
438
|
-
>>> st.
|
482
|
+
>>> message = st.text_area("Message", value="Lorem ipsum.\nStreamlit is cool.")
|
483
|
+
>>>
|
484
|
+
>>> if st.button("Prepare download"):
|
485
|
+
>>> st.download_button(
|
486
|
+
... label="Download text",
|
487
|
+
... data=message,
|
488
|
+
... file_name="message.txt",
|
489
|
+
... on_click="ignore",
|
490
|
+
... type="primary",
|
491
|
+
... icon=":material/download:",
|
492
|
+
... )
|
493
|
+
|
494
|
+
.. output::
|
495
|
+
https://doc-download-button-text.streamlit.app/
|
496
|
+
height: 250px
|
439
497
|
|
440
|
-
Download
|
498
|
+
**Example 3: Download a file**
|
499
|
+
|
500
|
+
Use a context manager to open and read a local file on your Streamlit
|
501
|
+
server. Pass the ``io.BufferedReader`` object directly to ``data``.
|
502
|
+
Remember to specify the MIME type if you don't want the default
|
503
|
+
type of ``"application/octet-stream"`` for generic binary data. In the
|
504
|
+
example below, the MIME type is set to ``"image/png"`` for a PNG file.
|
441
505
|
|
442
506
|
>>> import streamlit as st
|
443
507
|
>>>
|
444
508
|
>>> with open("flower.png", "rb") as file:
|
445
|
-
...
|
509
|
+
... st.download_button(
|
446
510
|
... label="Download image",
|
447
511
|
... data=file,
|
448
512
|
... file_name="flower.png",
|
@@ -450,8 +514,8 @@ class ButtonMixin:
|
|
450
514
|
... )
|
451
515
|
|
452
516
|
.. output::
|
453
|
-
https://doc-download-
|
454
|
-
height:
|
517
|
+
https://doc-download-button-file.streamlit.app/
|
518
|
+
height: 200px
|
455
519
|
|
456
520
|
"""
|
457
521
|
ctx = get_script_run_ctx()
|